<?php
/**
 * 路由定义
 *
 * @package if
 * @subpackage controller
 * @since 1.0
 */
class IRouter extends IObject {
	private $standardPath;
	private $router;
	private $uniqueKey = array();
	
	/**
	 * 启动路由
	 *
	 * @since 1.0
	 */
	function start() {
		$request = IRequest::singleton();
		$realpath = IF_ACTION_PATH;
		$ext = o("@router.ext");
		if ($ext != "") {
			$realpath = preg_replace("/\." . preg_quote($ext, "/") . "$/", "", $realpath);
		}
		
		//初始化
		$controllerName = null;
		$actionName = null;
		$params = array();
		
		//从配置中获取controller/action 
		$patterns = o("@router.patterns");
		if (is_array($patterns)) {
			foreach ($patterns as $pattern) {
				if (preg_match("{" . $pattern["path"] . "}", $realpath, $match)) {
					foreach ($pattern as $argKey=>$argValue) {
						if (if_is_valid_variable_name($argKey)) {
							if ($argKey == "controller") {
								$argKey = "controllerName";
							}
							if ($argKey == "action") {
								$argKey = "actionName";
							}
							if (is_scalar($argValue)) {
								$$argKey = @preg_replace("|\\$(\\d+)|e", "\$match[\\1]", $argValue);					}
							if ($argKey == "params" && is_array($argValue)) {
								foreach ($argValue as $pKey => $pValue) {
									if (is_array($pValue)) {
										$params[$pKey] = $pValue;
									}
									else if (is_scalar($pValue)) {
										$params[$pKey] = @preg_replace("|\\$(\\d+)|e", "\$match[\\1]", $pValue);		
									}
								}
							}
						}
					}		
					$this->uniqueKey = array(
						"path" => ($pattern["path"][0] == "^")?"^" . __ROUTER__ . substr($pattern["path"], 1):__ROUTER__ . $pattern["path"],
						"key" => @$pattern["controller"] . "." . @$pattern["action"]
					);		
					break;//找到即跳出
				}
			}
		}
		
		//从查询中获取
		if (!$controllerName) {
			$controllerName = $request->param(IController::controllerKeyword());
			$actionName = $request->param(IController::actionKeyword());
		}
		
		//从路径中获取
		if (!$controllerName) {
			$controllerAction = $this->parsePath($realpath, $params);
			if (!empty($controllerAction)) {
				$controllerName = $controllerAction["controller"];
				$actionName = $controllerAction["action"];
			}
		}
		
		//没有找到
		if (!$controllerName) {
			throw new IActionNotFoundException("unknown route '{$realpath}'", 0x100040);
		}

		//查找对应的类
		$controller = $this->findController($controllerName, $actionName);
		
		//匹配的规则
		if (empty($this->uniqueKey)) {
			if (preg_match("{^((/\w+)+)/\d+/?$}", $realpath, $match)) {
				$this->uniqueKey = array(
					"path" => "^" .  __ROUTER__ . $match[1] . "/\d+/?$",
					"key" => str_replace("/", ".", ltrim($match[1], "/"))
				);
			}
			else if (preg_match("{^((/\w+)+)/?$}", $realpath, $match)) {
				$this->uniqueKey = array(
					"path" => "^" . __ROUTER__ . $match[1] . "/?$",
					"key" => str_replace("/", ".", ltrim($match[1], "/"))
				);
			}
			else if ($realpath == "" || $realpath == "/") {
				$this->uniqueKey = array(
					"path" => "^" . __ROUTER__ . "/?$",
					"key" => $controller->name() . "." . $controller->action()->name(),
				);
			}
		}
		$GLOBALS["COMPILER_UNIQUE_KEY"] = $this->uniqueKey;
		
		//执行
		$request->addParams($params);
		$controller->setRouter($this);
		$controller->addParams($params);
		$controller->exec();
	}
	
	/**
	 * 查找控制器
	 *
	 * @param string $controller 控制器名
	 * @param string $action 动作名
	 * @return Icontroller
	 * @since 1.0
	 */
	function findController($controller, $action) {
		if ($action == "") {
			$action = IController::defaultAction();
		}
		$array = array();
		$array[] = array("controller" => $controller, "action" => $action);// a.b->c
		$array[] = array("controller" => $controller . "." . $action, "action" => IController::defaultAction());//a.b.c->index
		$array[] = array("controller" => $controller . "." . $action . ".index", "action" => IController::defaultAction());//a.b.c.index->index
		$obj = null;
		foreach ($array as $v) {
			$obj = IController::objByName($v["controller"]);
			if ($obj) {
				if (!if_is_instance_of($obj, "IController")) {
					throw new IException("controller class '" . get_class($obj) . "' must be inherited from IController", 0x100006);
				}
				$obj->setAction($v["action"]);
				$obj->setName($v["controller"]);
				
				break;
			}
		}
		if (!$obj) {
			throw new IActionNotFoundException("can not find controller named by '{$array[0]['controller']}' or '{$array[1]['controller']}' or '{$array[2]['controller']}'", 0x100041);
		}
		return $obj;
	}
	
	/**
	 * 取得控制器和指定动作对应的路径
	 *
	 * @param string $controller 控制器
	 * @param string $action 动作
	 * @param array|null $params 查询参数
	 * @param boolean $alias 是否计算省略的形式
	 * @return string
	 * @since 1.0
	 */
	function path($controller, $action, array $params = null, $alias = true) {
		//standard path
		$standardPath = o("@router.standard.path");
		if ($standardPath) {
			$this->standardPath = $standardPath;
		}
		if ($this->standardPath == "") {
			$this->standardPath = "/%{controller}/%{action}";
		}
		$controller = str_replace(".", "/", $controller);
		$action = str_replace(".", "/", $action);
		$path = str_replace("%{controller}", $controller, $this->standardPath);
		$path = str_replace("%{action}", $action, $path);

		//alias
		if ($alias) {
			$alias = o("@router.standard.alias");
			if (is_array($alias)) {
				foreach ($alias as $left=>$right) {
					$left = str_replace(array("%{controller}", "%{action}"), array($controller, $action), $left);				
					if ($left == $path) {
						$path = str_replace(array("%{controller}", "%{action}"), array($controller, $action), $right);
					}
				}
			}
		}
		
		//extension
		$ext = o("@router.ext");
		if ($ext != "") {
			$path .= "." . $ext;
		}
		
		//params
		if (is_array($params)) {
			if (isset($params["id"])) {
				$ids = $params["id"];
				unset($params["id"]);
				if (is_array($ids)) {
					$path .= "/" . implode("/", $ids);
				}
				else {
					$path .= "/" . $ids;
				}
			}
			
			$query = array();
			foreach ($params as $key=>$value) {
				if (is_array($value)) {
					foreach ($value as $_key => $_value) {
						$query[] = $key . "[{$_key}]=" . urlencode($_value);
					}
				}
				else {
					$query[] = $key . "=" . urlencode($value);
				}
			}
			if (!empty($params)) {
				$path .= "?" . implode("&", $query);
			}
		}
		return __ROUTER__ . $path;
	}
	
	/**
	 * 尝试从路径中得到控制器
	 *
	 * 尝试把 /a/b/c/d 转换为 a.b.c/d，返回
	 *    array(
	 * 			"controller" => "a.b.c",
	 * 			"action" => "d"
	 *    )
	 * 
	 * @param string $path URL中访问的路径
	 * @param array $params 参数集
	 * @return array
	 * @since 1.0
	 */
	function parsePath($path, &$params = array()) {
		$realUrl = trim($path, "/");
		if ($realUrl == "") {
			//默认控制器
			$defaultAction = o("@app.default_action");
			$controller = "index";
			$action = IController::defaultAction();
			if ($defaultAction != "") {
				if (strstr($defaultAction, ".")) {
					$pieces = explode(".", $defaultAction);
					$action = array_pop($pieces);
					$controller = implode(".", $pieces);
				}
				else {
					$controller = $defaultAction;
				}
			}
			$this->standardPath = __ROUTER__ . "/%{controller}/%{action}";
			return array("controller" => $controller, "action" => $action);
		}
		
		
		//分解控制器和动作
		$actionUrl = $realUrl;
		if (preg_match("/^(.*)((\/\d+)+)\/?$/U", $realUrl, $match)) {
			$actionUrl = $match[1];
			$idStr = trim($match[2], "/");
			$ids = explode("/", $idStr);
			if (count($ids) == 1) {
				IRequest::singleton()->addParam("id", $ids[0]);
			}
			else {
				IRequest::singleton()->addParam("id", $ids);
			}
		}

		if (!strstr($actionUrl, "/")) {
			//设置路径
			$this->standardPath = __ROUTER__ . "/%{controller}/%{action}";
			return array("controller" => $actionUrl, "action" => IController::defaultAction());
		}
	
		$pieces = explode("/", $actionUrl);
		$action = array_pop($pieces);		
		$this->standardPath = __ROUTER__ . "/%{controller}/%{action}";
		return array("controller" => implode(".", $pieces), "action" => $action);
	}
}

?>